/*
 * Copyright (c) 2020-2099 the original author or authors. All rights reserve.
 */
package org.tianyun.cloud.web.filters;

import org.apache.commons.lang3.StringUtils;
import org.tianyun.cloud.context.RequestContext.RequestContextHolder;
import org.tianyun.cloud.context.ServletContext;
import org.tianyun.cloud.context.ServletContext.ServletContextHolder;
import org.tianyun.cloud.ext.i18n.I18nMessageSource;
import org.tianyun.cloud.utils.RandomUtils;
import org.tianyun.cloud.web.WebConstantsConfiguration;
import org.tianyun.cloud.web.configuration.WebConfigProperties;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * Servlet上下文配置过滤器
 *
 * @auther ebert_chan
 */
public class ServletContextFilter extends AbstractFilter {

    private I18nMessageSource i18nMessageSource;

    private WebConfigProperties webConfigProperties;

    /**
     * constructor
     */
    public ServletContextFilter(WebConfigProperties webConfigProperties, I18nMessageSource i18nMessageSource) {
        this.webConfigProperties = webConfigProperties;
        this.i18nMessageSource = i18nMessageSource;
    }

    /*
     * @see org.springframework.core.Ordered#getOrder()
     */
    @Override
    public int getOrder() {
        return FILTER_SERVLET_CONTEXT_ORDERED;
    }

    /*
     * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest req = (HttpServletRequest) request;

        Enumeration<String> headerNames = req.getHeaderNames();
        Map<String, Object> contextValueMap = new HashMap<>();
        while (headerNames.hasMoreElements()) {
            String name = headerNames.nextElement();
            if (StringUtils.isEmpty(name) || !name.startsWith(ServletContext.CONTEXT_PROPERTY_PREFIX)) {
                continue;
            }
            String value = req.getHeader(name);
            contextValueMap.put(name, value);
        }

        // 从请求头中获取traceId（接续，用于服务间调用）
        String traceId = (String) contextValueMap.get(ServletContext.CONTEXT_TRACE_ID);
        if (StringUtils.isBlank(traceId) || traceId.length() != WebConstantsConfiguration.LOG_TRACE_LENGTH) {
            // 随机生成traceId
            traceId = RandomUtils.randomText(WebConstantsConfiguration.LOG_TRACE_LENGTH);
            contextValueMap.put(ServletContext.CONTEXT_TRACE_ID, traceId);
        }

        // 语言（接续，用于服务间调用）
        String language = (String) contextValueMap.get(ServletContext.CONTEXT_LANGUAGE);
        if (StringUtils.isBlank(language)) {
            language = req.getHeader(WebConstantsConfiguration.HEADER_X_HTTP_LANGUAGE);
            if (StringUtils.isBlank(language)) {
                language = req.getParameter(WebConstantsConfiguration.QUERY_LANGUAGE);
            }
        }
        if (StringUtils.isBlank(language) || !i18nMessageSource.containsLanguage(language)) {
            language = i18nMessageSource.getLocale();
        }
        contextValueMap.put(ServletContext.CONTEXT_LANGUAGE, language);

        try {
            // 添加响应头
            HttpServletResponse rsp = (HttpServletResponse) response;
            rsp.addHeader(WebConstantsConfiguration.HEADER_X_HTTP_TRACE, traceId);
            rsp.addHeader(WebConstantsConfiguration.HEADER_X_HTTP_LANGUAGE, language);

            // 添加到当前线程上下文中
            ServletContextHolder.setContextMap(contextValueMap);

            if (webConfigProperties.isDispatchRequestContext()) {
                String requestToken = req.getHeader(RequestContextHolder.HEADER_X_REQUEST_TOKEN);
                if (StringUtils.isNotEmpty(requestToken)) {
                    RequestContextHolder.setFromRequestToken(requestToken);
                }
            }

            // 往下传递
            chain.doFilter(request, response);

        } finally {
            // 清理上下文
            ServletContextHolder.clear();
        }
    }

}
